#include"recordFileMonitor.h"

const int PATH_SIZE=255;
namespace RecordManager{
#define Record_FILED "record."
const std::string kMaxStorageSpace=Record_FILED"maxStorageSpace";
const std::string kMaxStorageDays=Record_FILED"maxStorageDays";
onceToken token([]() {
    mINI::Instance()[kMaxStorageSpace] =0;
    mINI::Instance()[kMaxStorageDays] =0;
});
}
std::mutex videoPlatformApplication::videoPlatformApplication_mtx;
videoPlatformApplication::Ptr videoPlatformApplication::p_instance=nullptr;
std::multimap<time_t,std::string> videoPlatformApplication::_record_file_map;
std::string videoPlatformApplication::_dir="";
//std::future<void> videoPlatformApplication::diskMonitorFuture;
//std::future<void>  videoPlatformApplication::MaxtimeFuture;
Timer::Ptr g_recordtimemonitor_timer;
Timer::Ptr g_diskspacemonitor_timer;
videoPlatformApplication:: ~videoPlatformApplication(){

    if(g_recordtimemonitor_timer!=nullptr){
        g_recordtimemonitor_timer.reset();
    }
    if (g_diskspacemonitor_timer!=nullptr){
        g_diskspacemonitor_timer.reset();
    }
}
extern void onReportRecordFileDeleted(std::string filepath);

int videoPlatformApplication::init(){
    _dir = exeDir()+"/www/record/";
    if (_dir.back() != '/') {
        _dir.append("/");
    }
    //�ռ�����mp4�ļ�
    int numFile=0;
    File::scanDir(_dir, [&](const std::string &path, bool isDir) -> bool {;
        if (!isDir && end_with(path, ".mp4")) {
            if(path.size()>30 &&(path[path.size()-13]=='/'||path[path.size()-13]=='\\')&&(path[path.size()-24]=='/'||path[path.size()-24]=='\\' )){
                std::string timeStr=path.substr(path.size()-23,10)+"-"+path.substr(path.size()-12,8);
                struct tm tm_{0};
                if (strptime(timeStr.c_str(), "%Y-%m-%d-%H-%M-%S", &tm_)!=nullptr) {
                    _record_file_map.emplace(mktime(&tm_),path);
                    numFile++;
                }else{
                    InfoL<<"strptime fail";
                }
            }
        }
        return true;
    }, true);
    return 0;
}
int64_t getdictSize(std::string dicpath){
    int64_t sizeOfAll=0;
    File::scanDir(dicpath, [&](const std::string &path, bool isDir) {
        if(!isDir){
            sizeOfAll+=File::fileSize(path.c_str());
        }
        return true;
    },false);
    return sizeOfAll;
}

void  videoPlatformApplication::diskSpaceMonitor(){
    InfoL<<"start diskSpaceMonitor";
    diskMonitorFuture=std::async(std::launch::async,[&](){
        char path[PATH_SIZE];
        unsigned long long block_sizel=0,freesizel=0,totall=0,avail=0;
        if(!getcwd(path,PATH_SIZE)){
            ErrorL<<"Get path fail!"<< std::endl;
            return   ;
        }
        g_diskspacemonitor_timer=std::make_shared<Timer>(10, [&,path]() {
            GET_CONFIG(uint64_t,record_maxStorageSpace,RecordManager::kMaxStorageSpace);
            sleep(1);
            bool needDeal=false;
            struct statfs st;
            InfoL<<"start to check disk,path="<<path;
            if (statfs(path, &st) < 0) {
                ErrorL<<"record :: query Storage info fail!!!";
                return true;
            }
             std::string path_str=std::string(path);
            block_sizel=st.f_bsize;
            totall=st.f_blocks*block_sizel;
            freesizel=st.f_bfree*block_sizel;
            do{
                int flag=0;
                char str1[30],str2[30];
                flag=sprintf(str1,"%llu",totall>>20);
                flag=sprintf(str2,"%llu",freesizel>>20);
                if(10*freesizel<totall){
                    deleteRecordFile();
                }

                int64_t dicsize=getdictSize(path_str+"/www/record/");
                if (record_maxStorageSpace>0 && record_maxStorageSpace*1e9<dicsize){
                    deleteRecordFile();
                }

                if (statfs(path, &st) < 0) {
                    ErrorL<<"record::query Storage info fail!! ";
                    break;
                }
                block_sizel=st.f_bsize;
                totall=st.f_blocks*block_sizel;
                freesizel=st.f_bfree*block_sizel;
                needDeal=10*freesizel<totall||(record_maxStorageSpace>0 && record_maxStorageSpace*1e9<getdictSize(path_str+"/www/record/"));

            }while(needDeal);
            return true;
        }, nullptr);
    });

}
void  videoPlatformApplication::deleteFileByRecordTime(){
    GET_CONFIG(uint64_t,record_maxStorageDays,RecordManager::kMaxStorageDays);
    sleep(1);
    InfoL<<"record_maxStorageDays="<< record_maxStorageDays;
    InfoL<<"_record_file_map size="<< _record_file_map.size();
    for (auto it = _record_file_map.begin(); it != _record_file_map.end(); ) {
        bool needDeal=false;
        needDeal=it->first+3600*24*365 <std::time(NULL)||(record_maxStorageDays>0&&it->first+3600*24*record_maxStorageDays<std::time(NULL));
        if( needDeal){
            std::string filepath=it->second;
            File::delete_file(filepath.c_str());
            onReportRecordFileDeleted(filepath.c_str());
            it = _record_file_map.erase(it);
        }else{
            break;
        }
    }
}

void  videoPlatformApplication::recordTimeMonitor(){
    MaxtimeFuture=std::async(std::launch::async,[&](){
        deleteFileByRecordTime();
        g_recordtimemonitor_timer=std::make_shared<Timer>(3600*12,[&](){
            deleteFileByRecordTime();
            return true;

        }, nullptr);
});
}

int videoPlatformApplication::deleteRecordFile(std::string recordFilePath){
    int res=0;
    if(recordFilePath==""){
        auto it = _record_file_map.begin();
        if (it != _record_file_map.end()){
            std::string filepath=it->second;
            res=File::delete_file( filepath.c_str());
            _record_file_map.erase(it);
        }
    }else{
        res=File::delete_file(recordFilePath,true);
        for (auto it = _record_file_map.begin(); it != _record_file_map.end(); it++) {
            std::string filepath=it->second;
            if (it->second.find(recordFilePath)!=std::string::npos){
                it = _record_file_map.erase(it);
            }
        }
    }
    return res;
}
